﻿using MockCommon;
using MockDataAccess;
using System.Data;
using MockDataTransferObject;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace MockBusiness
{
    public class TimesheetBusiness
    {
        #region Initialize
        private static TimesheetBusiness _instance;
        private readonly TimesheetDataAccess _timesheetDataAccess;
        private readonly ContractDataAccess _contractDataAccess;
        private readonly TimesheetStatusDataAccess _timeSheetStatusDataAccess;

        /// <summary>
        /// Gets the time sheet data test.
        /// </summary>
        public Collection<Timesheet> TimesheetDataTest
        {
            get
            {
                return _timesheetDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Gets the contract data test.
        /// </summary>
        public Collection<Contract> ContractDataTest
        {
            get
            {
                return _contractDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Gets the time sheet status data test.
        /// </summary>
        public Collection<TimesheetStatus> TimesheetStatusDataTest
        {
            get
            {
                return _timeSheetStatusDataAccess.AffectedRows;
            }
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="TimesheetBusiness"/> class from being created.
        /// </summary>
        private TimesheetBusiness()
        {
            _timesheetDataAccess = new TimesheetDataAccess();
            _timeSheetStatusDataAccess = new TimesheetStatusDataAccess();
            _contractDataAccess = new ContractDataAccess();
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="TimesheetBusiness"/> class from being created.
        /// </summary>
        /// <param name="isFake">if set to <c>true</c> [is fake].</param>
        private TimesheetBusiness(bool isFake)
        {
            _timesheetDataAccess = new TimesheetDataAccess(isFake);
            _timeSheetStatusDataAccess = new TimesheetStatusDataAccess(isFake);
            _contractDataAccess = new ContractDataAccess(isFake);
        }

        /// <summary>
        /// Retrieves the instance.
        /// </summary>
        /// <returns></returns>
        public static TimesheetBusiness RetrieveInstance()
        {
            if (_instance == null)
                _instance = new TimesheetBusiness();
            return _instance;
        }

        /// <summary>
        /// Retrieves the instance.
        /// </summary>
        /// <param name="isFake">if set to <c>true</c> [is fake].</param>
        /// <returns></returns>
        public static TimesheetBusiness RetrieveInstance(bool isFake)
        {
            if (_instance == null)
                _instance = new TimesheetBusiness(isFake);
            return _instance;
        }
        #endregion

        #region CUD
        /// <summary>
        /// Inserts the specified timesheet.
        /// </summary>
        /// <param name="timesheet">The timesheet.</param>
        public void Insert(Timesheet timesheet)
        {
            //check timesheet null
            if (timesheet == null)
            {
                throw new MockException("Timesheet is null", "Business");
            }
            //check timesheet is existed
            if (_timesheetDataAccess.Exist(timesheet.TimesheetId))
            {
                throw new MockException("Timesheet was existed", "Business");
            }
            if (timesheet.WorkingTime < 1 || timesheet.WorkingTime > 23)
            {
                throw new MockException("Working time must in range 1-23", "Business");
            }
            DateTime today = DateTime.Now;
            Contract contract = timesheet.Contract;
            //contract null
            if (contract == null)
            {
                throw new MockException("Contract is null", "Business");
            }
            if (!_contractDataAccess.Exist(contract.ContractId))
            {
                throw new MockException("Contract is not existed", "Business");
            }
            if (today < contract.StartDate || today > contract.EndDate)
            {
                throw new MockException("Contract was expired", "Business");
            }
            //check timesheetdate
            if (timesheet.TimesheetDate < contract.StartDate || timesheet.TimesheetDate > contract.EndDate)
            {
                throw new MockException("Timesheet date is out of range", "Business");
            }
            if (!contract.IsActive)
            {
                throw new MockException("Contract was blocked", "Business");
            }  
            TimesheetStatus timesheetStatus = timesheet.Status;
            //check timesheetstatus null
            if (timesheet.Status == null)
            {
                throw new MockException("Timesheet status is null", "Business");
            }
            if (!_timeSheetStatusDataAccess.Exist(timesheetStatus.StatusId))
            {
                throw new MockException("Timesheet status was not existed", "Business");
            }
            _timesheetDataAccess.Create(timesheet);
        }

        /// <summary>
        /// Updates the specified timesheet.
        /// </summary>
        /// <param name="timesheet">The timesheet.</param>
        public void Update(Timesheet timesheet)
        {
            DateTime today = DateTime.Now;
            //check timesheet null
            if (timesheet == null)
            {
                throw new MockException("Timesheet is null", "Business");
            }
            //check timesheetid existed
            if (!_timesheetDataAccess.Exist(timesheet.TimesheetId))
            {
                throw new MockException("Timesheet was not existed", "Business");
            }
            if (timesheet.WorkingTime < 1 || timesheet.WorkingTime > 23)
            {
                throw new MockException("Working time must in range 1-23", "Business");
            }
            Contract contract = timesheet.Contract;
            //check is existed contract
            if (timesheet.Contract == null)
            {
                throw new MockException("Contract is null", "Business");
            }
            if (!_contractDataAccess.Exist(contract.ContractId))
            {
                throw new MockException("Contract was not existed", "Business");
            }
            if (!contract.IsActive)
            {
                throw new MockException("Contract was blocked", "Business");
            }
            if (today < contract.StartDate || today > contract.EndDate)
            {
                throw new MockException("Contract was expired", "Business");
            }
            //check timesheetdate
            if (timesheet.TimesheetDate < contract.StartDate || timesheet.TimesheetDate > contract.EndDate)
            {
                throw new MockException("Timesheet date is out of range", "Business");
            }
            //check timesheetstatus null
            if (timesheet.Status == null)
            {
                throw new MockException("Timesheet status is null", "Business");
            }
            if (!_timeSheetStatusDataAccess.Exist(timesheet.Status.StatusId))
            {
                throw new MockException("Timesheet status was not existed", "Business");
            }
            if (!_timesheetDataAccess.IsExistStatusName("Pending", timesheet.TimesheetId))
            {
                throw new MockException("Timesheet'status is not pending", "Business");
            }
            _timesheetDataAccess.Update(timesheet);
        }

        /// <summary>
        /// Deletes the specified timesheet id.
        /// </summary>
        /// <param name="timesheetId">The timesheet id.</param>
        public void Delete(Guid timesheetId)
        {
            string statusname = "Pending";
            if (!_timesheetDataAccess.Exist(timesheetId))
            {
                throw new MockException("Timesheet was not existed", "Business");
            }
            if (!_timesheetDataAccess.IsExistStatusName(statusname, timesheetId))
            {
                throw new MockException("Timesheet has been approved", "Business");
            }
            _timesheetDataAccess.Delete(timesheetId);
        }
        #endregion

        #region R
        /// <summary>
        /// Gets the by id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns></returns>
        public Timesheet GetById(object id)
        {
            if (id == null)
                return null;
            return _timesheetDataAccess.GetById(id);
        }

        /// <summary>
        /// Gets the name of all pending timesheet by client user.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        public Collection<Timesheet> GetAllPendingTimesheetByClientUserName(string userName)
        {
            if (userName == null)
                return null;
            return _timesheetDataAccess.GetByClientUserNameAndStatusName(userName, "Pending");
        }

        /// <summary>
        /// Timesheets the get by contractor id.
        /// </summary>
        /// <param name="contractorId">The contractor id.</param>
        /// <returns></returns>
        public Collection<Timesheet> TimesheetGetByContractorId(Guid contractorId)
        {
            return _timesheetDataAccess.GetByContractorId(contractorId);
        }

        /// <summary>
        /// Gets the name of the by contractor user.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <returns></returns>
        public Collection<Timesheet> GetByContractorUserName(string userName)
        {
            if (userName == null)
                return null;
            return _timesheetDataAccess.GetByContractorUserName(userName);
        }

        /// <summary>
        /// Gets the by filter.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <param name="statusId">The status id.</param>
        /// <returns></returns>
        public Collection<Timesheet> GetByFilter(string userName, Guid statusId)
        {
            if (userName == null || statusId == null)
                return null;
            return _timesheetDataAccess.GetByFilter(userName, statusId);
        }

        /// <summary>
        /// Gets the by filter range.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <param name="statusId">The status id.</param>
        /// <param name="fromDate">From date.</param>
        /// <param name="toDate">To date.</param>
        /// <returns></returns>
        public Collection<Timesheet> GetByFilterRange(string userName, Guid statusId, DateTime fromDate, DateTime toDate)
        {
            if (userName == null)
            {
                return null;
            }
            return _timesheetDataAccess.GetByFilterRange(userName, statusId, fromDate, toDate);
        }
        #endregion

        #region Others
        /// <summary>
        /// Checks the working time valid.
        /// </summary>
        /// <param name="time">The time.</param>
        /// <returns></returns>
        public static bool CheckWorkingTimeValid(int time)
        {
            if (time <= 0 || time > 23)
            {
                return false;
            }
            return true;
        }
        #endregion

    }
}
